﻿// -----------------------------------------------------------------------
// <copyright file="PpmHandler.cs" company="FCIS">
// You are welcome to do whatever you want with the code in this file
// </copyright>
// -----------------------------------------------------------------------

namespace ImagePackage.IO
{
    using System;
    using System.IO;

    /// <summary>
    /// Handles Encoding and Decoding of PPM files
    /// </summary>
    internal class PpmHandler
    {
        /// <summary>
        /// Decodes the specified file path.
        /// </summary>
        /// <param name="filePath">The file path.</param>
        /// <returns>Image model</returns>
        public Model.Image Decode(string filePath)
        {
            Model.Image image;
            var binaryReader = new BinaryReader(new FileStream(filePath, FileMode.Open));
            //// Header information
            string magicNumber = string.Empty;
            int width = -1;
            int height = -1;
            int depth = -1;

            //// Read the Header.
            int headerItemCount = 0;
            while (headerItemCount < 4)
            {
                char nextChar = (char)binaryReader.PeekChar();
                if (nextChar == '#')
                {
                    while (nextChar != '\n')
                    {
                        nextChar = binaryReader.ReadChar();
                    }
                }
                else if (char.IsWhiteSpace(nextChar))
                {
                    binaryReader.ReadChar();
                }
                else
                {
                    switch (headerItemCount)
                    {
                        case 0: // next item is Magic Number
                            // Read the first 2 characters and determine the type of pixelmap.
                            char[] chars = binaryReader.ReadChars(2);
                            magicNumber = chars[0] + chars[1].ToString();
                            headerItemCount++;
                            break;
                        case 1: // next item is the width.
                            width = this.ReadValue(binaryReader);
                            headerItemCount++;
                            break;
                        case 2: // next item is the height.
                            height = this.ReadValue(binaryReader);
                            headerItemCount++;
                            break;
                        case 3: // next item is the depth.
                            if (magicNumber == "P1" | magicNumber == "P4")
                            {
                                // no depth value for PBM type.
                                headerItemCount++;
                            }
                            else
                            {
                                depth = this.ReadValue(binaryReader);
                                headerItemCount++;
                            }

                            break;
                        default:
                            throw new Exception("Error parsing the file header.");
                    }
                }
            }

            image = new Model.Image(width, height);

            switch (magicNumber)
            {
                case "P1": break;
                case "P2": break;
                case "P3": break;
                case "P4": break;
                case "P5": break;
                case "P6": this.DecodeP6(binaryReader, image);
                    break;
                default:
                    throw new Exception("Un recognized ppm format");
            }

            return image;
        }

        /// <summary>
        /// Encodes the specified image.
        /// </summary>
        /// <param name="image">The image.</param>
        /// <param name="filePath">The file path.</param>
        /// <param name="ppmFormat">The PPM format.</param>
        public void Encode(Model.Image image, string filePath, PpmFormat ppmFormat)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Decodes the p6.
        /// </summary>
        /// <param name="binaryReader">The binary reader.</param>
        /// <param name="image">The image.</param>
        private void DecodeP6(BinaryReader binaryReader, Model.Image image)
        {
            for (int y = 0; y < image.Height; y++)
            {
                for (int x = 0; x < image.Width; x++)
                {
                    image[x, y] = new Model.Pixel(binaryReader.ReadByte(), binaryReader.ReadByte(), binaryReader.ReadByte());
                }
            }
        }

        /// <summary>
        /// Reads the binary integer value.
        /// </summary>
        /// <param name="binaryReader">The binary reader.</param>
        /// <returns>The integer value from binary</returns>
        private int ReadValue(BinaryReader binaryReader)
        {
            string value = string.Empty;
            while (!char.IsWhiteSpace((char)binaryReader.PeekChar()))
            {
                value += binaryReader.ReadChar().ToString();
            }

            binaryReader.ReadByte();   // get rid of the whitespace.
            return int.Parse(value);
        }
    }
}
